{
 "cells": [
  {
   "cell_type": "raw",
   "metadata": {
    "vscode": {
     "languageId": "raw"
    }
   },
   "source": [
    "---\n",
    "title: '`@parameter`'\n",
    "description: Executes a function or if statement at compile time.\n",
    "---"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can add the `@parameter` decorator on an `if` statement or on a nested\n",
    "function to run that code at compile time.\n",
    "\n",
    "## Parametric if statement\n",
    "\n",
    "You can add `@parameter` to any `if` condition that's based on a valid\n",
    "parameter expression (it's an expression that evaluates at compile time). This\n",
    "ensures that only the live branch of the `if` statement is compiled into the\n",
    "program, which can reduce your final binary size. For example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "this will be included in the binary\n"
     ]
    }
   ],
   "source": [
    "@parameter\n",
    "if True:\n",
    "    print(\"this will be included in the binary\")\n",
    "else:\n",
    "    print(\"this will be eliminated at compile time\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Parametric for statement\n",
    "\n",
    "You can add the `@parameter` decorator to an `for` loop to create a loop that's\n",
    "evaluated at compile time. The loop sequence and induction values must be\n",
    "a valid parameter expressions (that is, an expressions that evaluate at compile\n",
    "time).\n",
    "\n",
    "This has the effect of \"unrolling\" the loop.\n",
    "\n",
    "  ```mojo\n",
    "  fn parameter_for[max: Int]():\n",
    "      @parameter\n",
    "      for i in range(max)\n",
    "          @parameter\n",
    "          if i == 10:\n",
    "              print(\"found 10!\")\n",
    "  ```\n",
    "\n",
    "  Currently, `@parameter for` requires the sequence's `__iter__` method to\n",
    "  return a `_StridedRangeIterator`, meaning the induction variables must be\n",
    "  `Int`. The intention is to lift these restrictions in the future.\n",
    "\n",
    "### Compared to `unroll()`\n",
    "\n",
    "The Mojo standard library also includes a function called\n",
    "[`unroll()`](/mojo/stdlib/utils/loop/unroll) that unrolls a\n",
    "given function that you want to call repeatedly, but has some important\n",
    "differences when compared to the parametric `for` statement:\n",
    "\n",
    "- The `@parameter` decorator operates on `for` loop expressions. The \n",
    "  `unroll()` function is a higher-order function that takes a parametric closure\n",
    "  (see below) and executes it a specified number of times.\n",
    "\n",
    "- The parametric `for` statement is more versatile, since you can do anything \n",
    "  you can do in a `for` statement: including using arbitrary sequences, \n",
    "  early-exiting from the loop, skipping iterations with `continue` and so on.\n",
    "  \n",
    "  By contrast, `unroll()` simply takes a function and a count, and executes\n",
    "  the function the specified number of times.\n",
    "\n",
    "Both `unroll()` and `@parameter for` unroll at the beginning of compilation, \n",
    "which might explode the size of the program that still needs to be compiled,\n",
    "depending on the amount of code that's unrolled."
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Parametric closure\n",
    "\n",
    "You can add `@parameter` on a nested function to create a “parametric”\n",
    "capturing closure. This means you can create a closure function that captures\n",
    "values from the outer scope (regardless of whether they are variables or\n",
    "parameters), and then use that closure as a parameter. For example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3\n"
     ]
    }
   ],
   "source": [
    "fn use_closure[func: fn(Int) capturing -> Int](num: Int) -> Int:\n",
    "    return func(num)\n",
    "\n",
    "fn create_closure():\n",
    "    var x = 1\n",
    "\n",
    "    @parameter\n",
    "    fn add(i: Int) -> Int:\n",
    "        return x + i\n",
    "\n",
    "    var y = use_closure[add](2)\n",
    "    print(y)\n",
    "\n",
    "create_closure()"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Without the `@parameter` decorator, you'll get a compiler error that says you\n",
    "\"cannot use a dynamic value in call parameter\"—referring to the\n",
    "`use_closure[add](2)` call—because the `add()` closure would still be dynamic."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    ":::caution\n",
    "\n",
    "This is an unsafe feature because we currently do not model the lifetimes of\n",
    "capture-by-reference.\n",
    "\n",
    ":::"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<CommentService />"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Mojo",
   "language": "mojo",
   "name": "mojo-jupyter-kernel"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "mojo"
   },
   "file_extension": ".mojo",
   "mimetype": "text/x-mojo",
   "name": "mojo"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
